home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Tools 2
/
Amiga Tools 2.iso
/
tools
/
mg
/
src.lzh
/
amiga
/
menustack.c
< prev
next >
Wrap
C/C++ Source or Header
|
1990-05-23
|
10KB
|
378 lines
/*
* Simple menu package. Needs lotsa work to handle some cases.
*
* Copyright 1985 Louis A. Mamakos Software & Stuff 14813 Ashford Place Laurel,
* MD 20707
*
* For non-commerical use only. This program, or any modifications, may not be
* sold or incorporated into any product without prior permission from the
* author.
*
* Modified by mwm to handle "stacking" menus. NB - adding item to a menu that's
* been "popped" back to doesn't work, and probably never will. Modified
* again by MPK to allow subitems again (non-stacking), and fix bug when
* visiting files not in last menu.
*
* Modified once again by MPK to avoid calling strsave() if desired. This is
* controlled by the newly-added last parameter to *_Add(), which indicates
* whether the menu name should be saved off by strsave(). I suppose *not*
* saving strings might break on a system where MEMF_PUBLIC meant something,
* but I think that's far in the future...
*/
#include "do_menu.h"
#ifdef DO_MENU
#undef LATTICE
#undef MANX
#undef AZTEC
#include "compiler.h"
#include <exec/types.h>
#include <exec/nodes.h>
#include <exec/lists.h>
#include <exec/ports.h>
#include <exec/devices.h>
#include <exec/memory.h>
#include <hardware/blit.h>
#include <graphics/copper.h>
#include <graphics/regions.h>
#include <graphics/rastport.h>
#include <graphics/gfxbase.h>
#include <graphics/gels.h>
#include <intuition/intuition.h>
#ifdef LATTICE
#include <proto/all.h>
#else
#include <functions.h>
#endif
#undef TRUE
#undef FALSE
#include "def.h"
#ifdef ANSI
#include <string.h>
#endif
#define MNUM(menu,item,sub) (SHIFTMENU(menu)|SHIFTITEM(item)|SHIFTSUB(sub))
#define Menu_Clear DisposeMenus /* For ttyio.c */
struct Mem_Node {
struct Node mn_Node;
struct Remember *mn_Memory;
struct Menu *mn_Menu;
} *Top;
extern struct Screen WBInfo; /* For Screen width & Height */
#define SCREENHEIGHT (WBInfo . Height)
#define SCREENWIDTH (WBInfo . Width)
static struct List Memory;
static int Cur_Menu, Cur_MenuItem, Cur_SubItem;
static struct Menu *LastMenu;
static struct MenuItem *LastMenuItem, *LastSubItem;
struct Menu *AutoMenu; /* menu struct being dynamically built */
#ifdef MANX
char *strsave(); /* Save a string in the remember list */
#else
#define strsave(s) strdup(s)
#ifdef AZTEC
char *strdup PROTO((char *));
#endif
#endif
VOID
Menu_Init()
{
Memory.lh_Head = (struct Node *) & (Memory.lh_Tail);
Memory.lh_TailPred = (struct Node *) & (Memory.lh_Head);
Memory.lh_Tail = NULL;
Memory.lh_Type = NT_MEMORY;
Top = NULL;
Cur_Menu = Cur_MenuItem = Cur_SubItem = -1;
AutoMenu = LastMenu = NULL; /* no menu chain yet */
LastMenuItem = LastSubItem = NULL;
}
VOID
Menu_Clear()
{
while ((Top = (struct Mem_Node *) RemHead(&Memory)) != NULL) {
FreeRemember(&(Top->mn_Memory), (LONG) TRUE);
FreeMem(Top, (LONG) sizeof(struct Mem_Node));
}
Menu_Init(); /* Just for safeties sake */
}
VOID
Menu_Pop()
{
if ((Top = (struct Mem_Node *) RemHead(&Memory)) == NULL)
return;
FreeRemember(&(Top->mn_Memory), (LONG) TRUE);
FreeMem(Top, (LONG) sizeof(struct Mem_Node));
/* Now, set Top back to the real list head */
Top = (struct Mem_Node *) Memory.lh_Head;
LastMenu = Top->mn_Menu;
LastMenu->NextMenu = NULL; /* Tie off the menu list */
LastMenuItem = NULL; /* Wrong, but you can't add items here anyway */
LastSubItem = NULL; /* ditto */
Cur_Menu--;
}
/*
* Add a MENU item. Args are the text of the menu item, and an enable flag.
* Returns an Intuition type menu number, with the MenuItem and Menu SubItem
* being NOITEM and NOSUB. The MENUITEM part is valid.
*/
/* dummy Intuitext used to calculate length of menu names */
static struct IntuiText itd = {
AUTOFRONTPEN, AUTOBACKPEN, JAM2, 1, 1, NULL, NULL, NULL
};
int
Menu_Add(name, enabled, saveit)
char *name;
int enabled;
int saveit;
{
register struct Menu *m;
if (!name)
return 0;
if ((Top = (struct Mem_Node *) AllocMem(
(LONG) sizeof(struct Mem_Node), (LONG) MEMF_PUBLIC | MEMF_CLEAR)) == NULL)
return 0;
Top->mn_Node.ln_Type = NT_MEMORY;
if ((m = (struct Menu *) AllocRemember(&(Top->mn_Memory),
(LONG) sizeof(struct Menu), MEMF_PUBLIC | MEMF_CLEAR)) == NULL)
return 0;
Top->mn_Menu = m;
if (LastMenu == NULL)
AutoMenu = m; /* first menu on list */
else
LastMenu->NextMenu = m; /* link it in */
LastMenuItem = NULL; /* end of previous MenuItem list */
LastSubItem = NULL;
Cur_MenuItem = Cur_SubItem = -1; /* reset item numbers */
if (LastMenu == NULL)
m->LeftEdge = 0;
else
m->LeftEdge = LastMenu->LeftEdge + LastMenu->Width;
m->TopEdge = 0;
itd.IText = (UBYTE *) name;
m->Width = IntuiTextLength(&itd);
Top->mn_Node.ln_Name = m->MenuName = saveit ? strsave(name) : name;
m->Height = 0;
m->Flags = enabled ? MENUENABLED : 0;
m->FirstItem = NULL;
LastMenu = m;
AddHead(&Memory, (struct Node *) Top);
return MNUM(++Cur_Menu, NOITEM, NOSUB);
}
/*
* Add a menu item to the current MENU. Note that Add_Menu *must* be called
* before this function.
*/
int
Menu_Item_Add(name, flags, mux, ch, saveit)
char *name; /* name of menu item */
unsigned int flags;
LONG mux; /* mutual exclusion mask */
int ch; /* command sequence character, if COMMSEQ */
int saveit; /* save name using strsave? */
{
register struct MenuItem *m, *n;
register struct IntuiText *it;
if (!name)
return 0;
flags &= CHECKIT | CHECKED | COMMSEQ | MENUTOGGLE | ITEMENABLED | HIGHCOMP | HIGHBOX;
if (LastMenu == NULL)
return MNUM(NOMENU, NOITEM, NOSUB);
if ((m = (struct MenuItem *) AllocRemember(&(Top->mn_Memory),
(LONG) sizeof(struct MenuItem), (LONG) MEMF_PUBLIC | MEMF_CLEAR)) == NULL)
return MNUM(NOMENU, NOITEM, NOSUB);
LastSubItem = NULL; /* terminate possible list of subitems */
Cur_SubItem = -1;
if (LastMenuItem == NULL)
LastMenu->FirstItem = m;
else
LastMenuItem->NextItem = m;
m->Flags = flags | ITEMTEXT;
/*
* Check for highlight mode: if none selected, use HIGHCOMP
*/
if ((m->Flags & (HIGHCOMP | HIGHBOX)) == 0)
m->Flags |= HIGHCOMP;
m->Command = ch;
m->MutualExclude = mux;
m->SubItem = NULL;
m->ItemFill = (APTR) AllocRemember(&(Top->mn_Memory),
(LONG) sizeof(struct IntuiText), (LONG) MEMF_PUBLIC | MEMF_CLEAR);
it = (struct IntuiText *) m->ItemFill;
it->FrontPen = AUTOFRONTPEN;
it->BackPen = AUTOBACKPEN;
it->DrawMode = JAM2;
if (flags & CHECKIT)
it->LeftEdge = CHECKWIDTH + 1;
else
it->LeftEdge = 1;
it->TopEdge = 1;
it->ITextFont = NULL; /* default font */
it->IText = (UBYTE *) (saveit ? strsave(name) : name);
it->NextText = NULL;
if (LastMenuItem == NULL) {
m->TopEdge = 2;
m->LeftEdge = 0;
} else if (LastMenuItem->TopEdge + 40 > SCREENHEIGHT) {
m->TopEdge = 2;
m->LeftEdge = LastMenuItem->LeftEdge + LastMenuItem->Width + 12;
if (m->LeftEdge > SCREENWIDTH) {
LastMenuItem->NextItem = NULL;
LastMenuItem->Flags &= ~ITEMENABLED;
return MNUM(NOMENU, NOITEM, NOSUB);
}
} else {
m->TopEdge = LastMenuItem->TopEdge + 10;
m->LeftEdge = LastMenuItem->LeftEdge;
}
m->Width = 0;
if (flags & CHECKIT)
m->Width += CHECKWIDTH;
if (flags & COMMSEQ)
m->Width += COMMWIDTH + 20;
m->Width += IntuiTextLength((struct IntuiText *) m->ItemFill);
m->Height = 10;
/*
* Check last menu item's width to see if it is larger than this
* item's. If new item is larger, then update width of all other
* items.
*/
if (LastMenuItem) {
if (LastMenuItem->Width > m->Width)
m->Width = LastMenuItem->Width;
else {
register short delta = m->Width - LastMenuItem->Width;
for (n = LastMenu->FirstItem; n != m; n = n->NextItem) {
n->Width = m->Width;
if (n->LeftEdge > 0)
n->LeftEdge += delta;
}
if (m->LeftEdge > 0)
m->LeftEdge += delta;
}
}
LastMenuItem = m;
return MNUM(Cur_Menu, ++Cur_MenuItem, NOSUB);
}
int
Menu_SubItem_Add(name, flags, mux, ch, saveit)
char *name;
unsigned int flags;
LONG mux;
int ch;
int saveit;
{
register struct MenuItem *m, *n;
register struct IntuiText *it;
if (!name)
return 0;
flags &= CHECKIT | CHECKED | COMMSEQ | MENUTOGGLE | ITEMENABLED | HIGHCOMP | HIGHBOX;
if (LastMenuItem == NULL)
return MNUM(NOMENU, NOITEM, NOSUB);
if ((m = (struct MenuItem *) AllocRemember(&(Top->mn_Memory),
(LONG) sizeof(struct MenuItem), (LONG) MEMF_PUBLIC | MEMF_CLEAR)) == NULL)
return MNUM(NOMENU, NOITEM, NOSUB);
if (LastSubItem == NULL)
LastMenuItem->SubItem = m;
else
LastSubItem->NextItem = m;
m->Flags = flags | ITEMTEXT;
/*
* check for highlight mode. If none selected, use HIGHCOMP
*/
if ((m->Flags & (HIGHCOMP | HIGHBOX)) == 0)
m->Flags |= HIGHCOMP;
m->Command = ch;
m->MutualExclude = mux;
m->SubItem = NULL;
m->ItemFill = (APTR) AllocRemember(&(Top->mn_Memory),
(LONG) sizeof(struct IntuiText), (LONG) MEMF_PUBLIC | MEMF_CLEAR);
it = (struct IntuiText *) m->ItemFill;
it->FrontPen = AUTOFRONTPEN;
it->BackPen = AUTOBACKPEN;
it->DrawMode = JAM2;
if (flags & CHECKIT)
it->LeftEdge = CHECKWIDTH + 1;
else
it->LeftEdge = 1;
it->TopEdge = 1;
it->ITextFont = NULL; /* default font */
it->IText = (UBYTE *) (saveit ? strsave(name) : name);
it->NextText = NULL;
m->LeftEdge = LastMenuItem->Width + 10;
m->Width = 0;
if (LastSubItem == NULL)
m->TopEdge = 1;
else
m->TopEdge = LastSubItem->TopEdge + 10;
if (flags & CHECKIT)
m->Width += CHECKWIDTH;
if (flags & COMMSEQ)
m->Width += COMMWIDTH + 20;
m->Width += IntuiTextLength((struct IntuiText *) m->ItemFill);
m->Height = 10;
/*
* Check last menu item's width to see if it is larger than this
* item's. If new item is larger, then update width of all other
* items.
*/
if (LastSubItem) {
if (LastSubItem->Width > m->Width)
m->Width = LastSubItem->Width;
else
for (n = LastMenuItem->SubItem; n != m; n = n->NextItem)
n->Width = m->Width;
}
LastSubItem = m;
return MNUM(Cur_Menu, Cur_MenuItem, ++Cur_SubItem);
}
#ifdef MANX
char *
strsave(string)
char *string;
{
char *out;
out = (char *) AllocRemember(&(Top->mn_Memory), (LONG) (strlen(string) + 1),
(LONG) MEMF_PUBLIC);
if (out == NULL)
return NULL;
(void) strcpy(out, string);
return out;
}
#endif
#else
#include "nullfile.h"
#endif